package Game.Objects.Creatures;

import java.lang.reflect.InvocationTargetException;
import java.util.Random;

import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;

import Game.GameHelper;
import Game.Items.GameItem;
import Game.Items.Armors.Helmets.GIRustyHelmet;
import Game.Items.Craft.GIBone;
import Game.Items.Potions.GISmallHealthPotion;
import Game.Items.Weapons.GIRustySword;
import Game.MapBlock.EMapBlockType;
import Game.Objects.GOPlayer;
import Game.Objects.GameObject;
import Game.Objects.ObjectManager;
import GameMath.GPoint;
import GameMath.GRandom;
import GameMath.GSize;

/** Skeleton
 * @author Aikidos
 */
public class GOCSkeleton extends GOCreature {

	/** Range of aggression */
	private int _rangeOfAggression = 3;
	
	/** Walk radius */
	private int _walkRadius = 5;

	public GOCSkeleton(ObjectManager objectManager) throws SlickException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException {
		super(objectManager, "Skeleton");
		
		setSprite(new Image("res/gfx/creatures/skeleton.png"));
		
		Type = EGameObjectType.Enemy;
		
		MaxHealth = 10;
		setHealth(MaxHealth);
		
		Magic = 7;
		Experience = 10;
		
		// Set default damage
		MinDamage = 1;
		MaxDamage = 2;
		
		// Add weapon
		GameItem defaultWeapon = getInventory().addItem(new GIRustySword(), 100);
		getInventory().useItem(defaultWeapon);
		
		// Add armor
		GameItem defaultHelmet = getInventory().addItem(new GIRustyHelmet(), 100);
		getInventory().useItem(defaultHelmet);
		
		// Add other items
		getInventory().addItem(new GISmallHealthPotion(), 100);
		getInventory().addItem(new GIBone(), 500);
	}

	@Override
	public void step() throws SlickException {
		super.step();
		
		boolean goToPlayer = false;
		boolean goToAlly = false;
		
		// Find player
		goToPlayer = stepFindPlayer();
		
		// Else find ally
		if (!goToPlayer) {
			goToAlly = stepFindAlly();
		}
		
		// Else go to random coordinate
		if (!goToPlayer && !goToAlly && (getWalkPath().size() == 0)) {
			stepGoToRandomCoord();
		}
		
		walk();
	}

	@Override
	public boolean onCollision(GameObject other, boolean moveOn) {
		if (other.isCreature())
		{
			GOCreature creature = (GOCreature) other;
			if (creature.Type == EGameObjectType.Ally)
			{
				if (moveOn) attack(other);
				return false;
			}
		}
		else if (other.isPlayer())
		{
			if (moveOn) attack(other);
			
			return false;
		}
		
		return true;
	}
	
	/** Find player and go to him
	 * @return true if player is found
	 */
	private boolean stepFindPlayer() {
		GOPlayer player = _objectManager.getPlayer();
		int distance = _objectManager.getLevel().getMap().getDistance(getCoord(), player.getCoord());
		if ((distance != -1) && (distance <= _rangeOfAggression)) {
			go(player.getCoord());
			return true;
		}
		
		return false;
	}
	
	/** Find ally mob and go to him
	 * @return true if ally mob is found
	 */
	private boolean stepFindAlly() {
		for (GameObject gameObject : _objectManager.getObjects()) {
			if (gameObject.isCreature() && (((GOCreature) gameObject).Type == EGameObjectType.Ally)) {
				int distance = _objectManager.getLevel().getMap().getDistance(getCoord(), gameObject.getCoord());
				if ((distance != -1) && (distance <= _rangeOfAggression)) {
					go(gameObject.getCoord());
					return true;
				}
			}
		}
		
		return false;
	}
	
	private void stepGoToRandomCoord() {
		// Get map size
		GSize mapSize = _objectManager.getLevel().getMap().getSize();

		// Go to random coordinates
		Random rnd = GameHelper.getRandom();
		
		GPoint p = new GPoint();
		while (true) {
			p = new GPoint(GRandom.nextInt(getCoord().x
					- _walkRadius, getCoord().x
					+ _walkRadius), GRandom.nextInt(
					getCoord().y - _walkRadius,
					getCoord().y + _walkRadius));

			if ((p.x >= 0) && (p.x < mapSize.width) && (p.y >= 0)
					&& (p.y < mapSize.height)) {
				if (_objectManager.getLevel().getMap().getBlocks()[p.x][p.y].Type == EMapBlockType.Floor) {
					int d = _objectManager.getLevel().getMap()
							.getDistance(getCoord(), p);
					if ((d != -1) && (d <= _walkRadius))
						break;
				}
			}
		}

		go(p);
	}
}
